package dados;

import java.io.File;
import java.io.Serializable;
import java.util.*;

import sistema.Verificador;

/**
 * Classe Evento que descreve um evento e suas caracteristicas
 */

public class Evento implements Comparable<Evento> ,Serializable{
	private static final long serialVersionUID = 1L;
	private String nome,data,horario,duracao,descricao,tipo;
	private List<Contato> contatosRelacionados = new ArrayList<Contato>();
	private List<File> fotos = new ArrayList<File>(), anotacoesAudio = new ArrayList<File>();
	private List<Anotacao> anotacoes = new ArrayList<Anotacao>();
	private final String STRING_VAZIA="";

	/**
	 * Cria um evento 
	 * @param nome Nome do evento
	 * @param data Data do evento do tipo dd/mm/aaaa
	 * @param horario Horario do evento do tipo hh:mm ex: 20:00
	 * @param duracao Duracao do evento do tipo hh:mm ex: 02:00
	 * @param descricao Descricao do evento
	 * @throws Exception Exceção caso um dos parametros seje nulo, ou em formato invalido.Note que a data pode ser do formato dd/mm/aaaa ou dd/mm
	 */
	public Evento(String nome, String data, String horario, String duracao,String descricao)throws Exception{

		if(nome==null || data==null || horario==null || duracao==null|| descricao==null){
			throw new Exception("Os parametros tem que ser passados corretamente");
		}
		if(!(Verificador.ehDataComAnoValida(data) || Verificador.ehDataSemAnoValida(data))){
			throw new Exception("formato de data invalido\nDigite na forma: dd/mm/aaaa");
		}
		if(!(Verificador.ehHorarioValido(horario))){
			throw new Exception("horario invalido.\nDigite na forma: hh:mm");
		}
		if(!(Verificador.ehHorarioValido(duracao))){
			throw new Exception("duracao invalida.\nDigite na forma: hh:mm");
		}

		this.data=data;
		this.duracao=duracao;
		this.horario=horario;
		this.nome=nome;
		this.descricao=descricao;
		this.tipo="";

	}

	/**
	 * Adiciona um contato, de modo que fique relacionado a um evento
	 * @param contato Contato a ser relacionado
	 */
	// adiciona um contato de modo a ficar relacionado a um envento
	public void AdicionaContatoAEvento(Contato contato){	
		contatosRelacionados.add(contato);

	}
	/**
	 * Adiciona anotacao a lista de anotacoes do evento corrente
	 * @param anotacao A anotacao que deseja ser anexada ao evento
	 */
	public void adicionaAnotacao(String anotacao){
		anotacoes.add(new Anotacao(anotacao));
		Collections.sort(anotacoes);
	}
	
	/**
	 * Adiciona anotacao a lista de anotacoes do evento corrente
	 * @param note
	 */
	public void adicionaAnotacao(Anotacao note){
		anotacoes.add(note);
		Collections.sort(anotacoes);
	}
	
	/**
	 * Remove uma anotacao da lista de anotacoes do evento corrente
	 * @param posicao
	 */
	public void removerAnotacao(int posicao){
		anotacoes.remove(posicao);
		Collections.sort(anotacoes);
	}
	
	/**
	 * Recupera o nome do evento
	 * @return O nome do evento
	 */
	public String getNome() {
		return nome;
	}
	/**
	 * Altera o nome do evento
	 * @param nome Novo nome do enveto
	 */
	public void setNome(String nome) {
		this.nome = nome;
	}
	/**
	 * Recupera a data do evento
	 * @return A data do evento
	 */
	public String getData() {
		return data;
	}
	/**
	 * Altera a data do evento.
	 * @param data Nova data do evento
	 */
	public void setData(String data) {
		this.data = data;
	}
	/**
	 * Recupera o horario do evento
	 * @return O horario do evento
	 */
	public String getHorario() {
		return horario;
	}
	/**
	 * Altera o horario do evento. Formato do horario hh:mm
	 * @param horario Novo horario do evento
	 */
	public void setHorario(String horario) {
		this.horario = horario;
	}
	/**
	 * Recupera a duracao do evento
	 * @return A duracao do evento
	 */
	public String getDuracao() {
		return duracao;
	}
	/**
	 * Altera a duracao do evento
	 * @param duracao Nova duracao do evento
	 */
	public void setDuracao(String duracao) {
		this.duracao = duracao;
	}
	/**
	 * Recupera a descricao do evento
	 * @return A descricao do evento
	 */
	public String getDescricao() {
		return descricao;
	}
	/**
	 * altera a descricao do evento
	 * @param descricao Nova descricao do evento
	 */
	public void setDescricao(String descricao) {
		this.descricao =STRING_VAZIA;
		this.descricao=descricao;
	}
	/**
	 * Recupera as anotacoes do evento
	 * @return A anotacao do evento
	 */
	public List<Anotacao> getAnotacoes() {
		return anotacoes;
	}
	/**
	 * Modifica as anotacoes do evento
	 * @param anotacao Nova anotacao do evento
	 */
	public void setAnotacao(List<Anotacao> anotacoes) {
		this.anotacoes = anotacoes;
	}
	/**
	 * Retorna o tipo do evento, caso exista, vazio caso nao exista
	 * @return O tipo do evento
	 */
	public String getTipo(){
		return tipo;
	}
	/**
	 * altera o tipo do evento
	 * @param tipo Novo tipo do evento
	 */
	public void setTipo(String tipo) {
		this.tipo = tipo;
	}
	/**
	 * Recupera os contatos associados ao evento
	 * @return Os contatos associados ao evento
	 */
	public List<Contato> getContatosRelacionados() {
		return contatosRelacionados;
	}


	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((data == null) ? 0 : data.hashCode());
		result = prime * result
		+ ((descricao == null) ? 0 : descricao.hashCode());
		result = prime * result + ((duracao == null) ? 0 : duracao.hashCode());
		result = prime * result + ((horario == null) ? 0 : horario.hashCode());
		result = prime * result + ((nome == null) ? 0 : nome.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof Evento))
			return false;
		Evento other = (Evento) obj;
		if (data == null) {
			if (other.data != null)
				return false;
		} else if (!data.equals(other.data))
			return false;
		if (descricao == null) {
			if (other.descricao != null)
				return false;
		} else if (!descricao.equals(other.descricao))
			return false;
		if (duracao == null) {
			if (other.duracao != null)
				return false;
		} else if (!duracao.equals(other.duracao))
			return false;
		if (horario == null) {
			if (other.horario != null)
				return false;
		} else if (!horario.equals(other.horario))
			return false;
		if (nome == null) {
			if (other.nome != null)
				return false;
		} else if (!nome.equals(other.nome))
			return false;
		return true;
	}

	/**
	 * Adiciona nova foto ao album de fotos do evento
	 * @param foto
	 */
	public void adicionarFoto(File foto){
		fotos.add(foto);
	}

	/**
	 * Recupera as fotos do album de fotos do evento
	 * @return
	 */
	public List<File> getFotos(){
		return fotos;
	}

	/**
	 * Modifica a lista de fotos do evento
	 * @param listFotos
	 */
	public void setFotos(List<File> listFotos){
		fotos = listFotos;
	}

	public void adicionaAudio(File audio){
		anotacoesAudio.add(audio);
	}
	
	public List<File> getAudio(){
		return anotacoesAudio;
	}
	
	public void setAudio(List<File> listAudio){
		anotacoesAudio = listAudio;
	}
	
	/**
	 * Recupera informacoes sobre o evento
	 */
	@Override
	public String toString() {
		return "Nome: " + nome +", "+ data;
	}

	/**
	 * Compara dois eventos por horario inicial, o evento "Maior" eh o mais novo.
	 */
	@Override
	public int compareTo(Evento outro) {
		String data1,data2,hora1,hora2;
		data1 = getData();
		data2 = outro.getData();
		hora1 = getHorario(); 
		hora2 = outro.getHorario();
		return comparaDataeHora(data1, hora1, data2, hora2);
	}

	private int comparaDataeHora(String data1,String hora1,String data2,String hora2){
		if (data1.length()== 10 && data2.length()==10){
			if (!(data1.substring(6).equals(data2.substring(6)))){
				return - Integer.parseInt(data2.substring(6)) + Integer.parseInt(data1.substring(6));
			}
		}
		if (!(data1.substring(3,5).equals(data2.substring(3,5)))){
			return - Integer.parseInt(data2.substring(3,5)) + Integer.parseInt(data1.substring(3,5));
		}
		if (!(data1.substring(0,2).equals(data2.substring(0,2)))){
			return - Integer.parseInt(data2.substring(0,2)) + Integer.parseInt(data1.substring(0,2));
		}
		if (!(hora1.substring(0,2).equals(hora2.substring(0,2)))){
			return - Integer.parseInt(hora2.substring(0,2)) + Integer.parseInt(hora1.substring(0,2));
		}
		if (!(hora1.substring(3).equals(hora2.substring(3)))){
			return - Integer.parseInt(hora2.substring(3)) + Integer.parseInt(hora1.substring(3));
		}
		return 0;
	}
	/**
	 * Retorna um array de 2 elementos contendo o horario e datas finais do evento.
	 * @return String[] {horarioFinal,dataFinal}.
	 */
	protected String[] horarioEDataFinal(){
		String[] retorno = new String[2];
		int hora,min,horaDuracao,minDuracao;
		hora = Integer.parseInt(horario.substring(0,2));
		min =  Integer.parseInt(horario.substring(3));
		horaDuracao = Integer.parseInt(duracao.substring(0,2));
		minDuracao =  Integer.parseInt(duracao.substring(3));
		min = min + minDuracao;
		if (min >=60){
			min = min - 60;
			hora ++;
		}
		hora = hora + horaDuracao;
		if(hora < 24){
			retorno[0] = String.format("%02d:%02d", hora,min);
			retorno[1] = getData();
			return retorno;
		}
		hora = hora - 24;
		String data = getData();
		int dia = Integer.parseInt(data.substring(0, 2));
		int mes = Integer.parseInt(data.substring(3,5));
		int ano = Integer.parseInt(data.substring(6));
		dia = dia + 1;
		String data2 = String.format("%02d/%02d/%04d", dia,mes,ano);
		if (Verificador.ehDataComAnoValida(data2)){
			retorno[0] = String.format("%02d:%02d", hora,min);
			retorno[1] = data2;
			return retorno;
		}
		if (Verificador.ehDataComAnoValida(data2)){
			data2 = String.format("01/%02d", mes+1);
			retorno[0] = String.format("%02d:%02d", hora,min);
			retorno[1] = data2;
			return retorno;
		}
		data2 = String.format("01/01/%04d", ano+1);
		retorno[0] = String.format("%02d:%02d", hora,min);
		retorno[1] = data2;
		return retorno;
	}
	/**
	 * Checa se dois eventos tem conflito de horario.
	 * @param outro o Evento a ser comparado.
	 * @return true se ha choque de horario, falso caso contrario.
	 */
	public boolean temConflitoDeHorario(Evento outro){
		String dataI1 = getData();
		String horaI1 = getHorario();
		String dataF1 = horarioEDataFinal()[1];
		String horaF1 = horarioEDataFinal()[0];
		String dataI2 = outro.getData();
		String horaI2 = outro.getHorario();
		String dataF2 = outro.horarioEDataFinal()[1];
		String horaF2 = outro.horarioEDataFinal()[0];

		if (comparaDataeHora(dataF1, horaF1, dataI2, horaI2) <= 0
				|| comparaDataeHora(dataF2, horaF2, dataI1, horaI1) <= 0){
			return false;
		}
		return true;
	}

}
